<?php

/**
 * apache dashboard
 *
 * PHP versions 5
 *
 * LICENSE:
 * See http://www.opensource.org/licenses/bsd-license.php
 *
 * DESCRIPTION:
 * gives a snapshot of what our apache farm is doing
 *
 * @author      Anton Visser <visseraj@gmail.com>
 * @version     1.1
 */

error_reporting(E_ALL & ~E_NOTICE);

/**
 * configuration - change the options below
*/

// restrict access to the following networks. Put an * to allow a range
$allowedIP = array('192.168.0.*', '192.168.10.1');

// domain name of your servers. This will be prepened by the servers names in the serverFarm array, when checking the status
$domainName = '.domain.com/server-status/';

// names of servers in the server farm
$serverFarm = array('web1', 'web2');

// how often do you want to refresh the page? In seconds.
$refreshSeconds = 7;

/**
 * don't change anything below
*/

$version = '1.1';
$scoreboard = array('W', 'K', '_', 'S', 'R', 'K', 'D', 'C', 'L', 'G', 'I', '.');
$stati = array();
$hostname = php_uname('n');
$hostname = explode('.', $hostname);
$currentServer = $hostname[0];

$tooltips = array(
    '_' => 'Waiting for Connection',
    'S' => 'Starting up',
    'R' => 'Reading Request',
    'W' => 'Sending Reply',
    'K' => 'Keepalive (read)',
    'D' => 'DNS Lookup',
    'C' => 'Closing connection',
    'L' => 'Logging',
    'G' => 'Gracefully finishing',
    'I' => 'Idle cleanup of worker',
    '.' => 'Open slot with no current process'
    );


// only allow from inside the following networks
$inNetwork = false;
foreach ($allowedIP as $ip) {
    if (preg_match('/^'.$ip.'/', $_SERVER['REMOTE_ADDR'])) {
        $inNetwork = true;
        break;
    }
}
if (!$inNetwork) {
    echo 'so sorry';
    exit;
}

// override the refresh time from cookie
if (isset($_COOKIE['refresh'])) {
    $refreshSeconds = $_COOKIE['refresh'];
}

foreach ($serverFarm as $server) {
    $stati[$server] = array();
    $stati[$server]['status'] = getStatus($server, $domainName);

    // figure out stats
    $stati[$server]['status'] = str_replace('HTTP/1.1','', $stati[$server]['status']);

    // apprently preg_match has a character limit, so only take the first part of the status report for what we need.
    $head = substr($stati[$server]['status'], 0, 2000);

    // summary
    preg_match('/<dt>(\d*.?\d+.*) requests\/sec - (\d+.*) \w*B\/second - (\d+.*) \w*B\/request<\/dt>/', $head, $summaryMatches);
    $stati[$server]['rps'] = $summaryMatches[1];
    $stati[$server]['mb'] = $summaryMatches[2];

    // pieces
    preg_match('/<pre>(.*)<\/pre>/is', $head, $pieces);
    foreach ($scoreboard as $k) {
        preg_match_all("/($k)/is", $pieces[1], $w);
        $stati[$server][$k] = count($w[1]);
    }

    // IP, vhost, files
    $ip = array();
    $vhost = array();
    $file = array();

    // figure out what is getting hit, and from where
    preg_match_all('/<td>(.*)<\/td><td nowrap>(.*)<\/td><td nowrap>(.*)<\/td><\/tr>/', $stati[$server]['status'], $matches);
    if (!empty($matches)) {
        foreach ($matches[1] as $k => $v) {
            $ip[$matches[1][$k]]++;
            $vhost[$matches[2][$k]]++;
            $file[$matches[3][$k]]++;
        }
    }
}

// calc vhost, ip, file summaries
foreach (array('ip','vhost','file') as $t) {
    arsort($$t);
    $$t = array_slice($$t, 0, 10);
    foreach ($$t as $k => $v) {
        if ($t == 'ip') {
            $html[$t] .= sprintf('%d => <a target="_blank" href="http://whois.arin.net/rest/nets;q=%s?showDetails=true&showARIN=false">%s</a><br/>', $v, $k, $k);
        } else {
            $html[$t] .= sprintf('%d => %s<br/>', $v, $k);
        }
    }
}

/**
 * get the status for a server
 *
 * @param string $server The server subdomain
 * @param string $domainName The domain name
 *
 * @return string
*/
function getStatus($server, $domainName) {
    $url = 'http://'.$server.$domainName;
    if (ini_get('allow_url_fopen') && function_exists('file_get_contents')) {
        $status = file_get_contents($url);
    } else if (function_exists('fsockopen')) {
        $timeout = 2;
        $remote_url     = parse_url($url);
        if (!isset($remote_url['port'])) {
            $remote_url['port'] = 80;
        }
        $remote_handler = fsockopen($remote_url['host'], $remote_url['port'], $c, $e, $timeout);

        if ($remote_handler) {
            stream_set_timeout($remote_handler, $timeout);

            if (isset($remote_url['query'])) {
                $remote_url['path'] .= '?' . $remote_url['query'];
            }

            $out = sprintf("GET %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: apache-dashboard\r\nConnection: Close\r\n\r\n",
                $remote_url['path'],
                $remote_url['host']
            );

            fwrite($remote_handler, $out);

            $response = fgets($remote_handler);
            if (strpos($response, '200 OK') !== false) {
                $file = '';
                while (!feof($remote_handler)) {
                    $file .= fgets($remote_handler);
                }

                $file = str_replace("\r\n", "\n", $file);
                $file = explode("\n\n", $file);
                array_shift($file);

                $status = implode("\n\n", $file);

                fclose($remote_handler);

            }
        }

    } else if (extension_loaded('curl')) {
        $ch = curl_init($url);

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_USERAGENT, 'apache-dashboard');

        $file = curl_exec($ch);

        curl_close($ch);

        if ($file !== false) {
            $status = $file;
        }

    } else {
        echo 'Your server is unable to remotely retrieve the status';
    }

    return $status;
}

?>


<html>
    <head>
        <title>Apache Dashboard :: v<?php echo $version ?></title>
        <META HTTP-EQUIV="Pragma" CONTENT="no-cache">
        <link rel="stylesheet" type="text/css" href="css/base.css" media="screen, projection" />
        <link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.12/themes/smoothness/jquery-ui.css" />
        <link rel="stylesheet" type="text/css" href="css/styles.css" media="screen, projection" />
    </head>
    <body>
        <div id="settings">
            <div id="title"><a href="http://code.google.com/p/apache-dashboard/" target="_blank">Apache Dashboard :: v<?php echo $version ?></a></div>
            <div onclick="controls()" id="progressbar"></div>
            <a href="javascript: void 0;" onclick="settings()">settings</a>&nbsp;
        </div>
        <div class="summary-noline">
            <h2>Summary</h2>
            <table width="100%" id="summaryTable">
                <tr>
                    <th></th>
                    <th title="requests/second">RPS</th>
                    <th title="MB/seccond">MB</th>
                    <?php foreach ($scoreboard as $s): ?>
                        <th title="<?php echo $tooltips[$s] ?>"><?php echo $s ?></th>
                    <?php endforeach; ?>
                </tr>
                <?php foreach ($stati as $key=>$server): ?>
                    <tr>
                        <td class="<?php echo $server['status'] ? 'up' : 'down' ?>"><?php echo $key == $currentServer ? '* ' : ''; echo $key ?></td>
                        <td><?php echo $server['rps']; $total['rps'] += $server['rps']; ?></td>
                        <td><?php echo $server['mb']; $total['mb'] += $server['mb']; ?></td>
                        <?php foreach ($scoreboard as $s): ?>
                            <td><?php echo $server[$s]; $total[$s] += $server[$s]; ?></td>
                        <?php endforeach; ?>
                    </tr>
                <?php endforeach; ?>
                <tr>
                    <th>Total</th>
                    <th><?php echo $total['rps']; ?></th>
                    <th><?php echo $total['mb']; ?></th>
                    <?php foreach ($scoreboard as $s): ?>
                        <th><?php echo $total[$s]; ?></th>
                    <?php endforeach; ?>
                </tr>
            </table>

        </div>

        <div class="summary-noline">
            <div class="summary">
                <h2>V-Hosts</h2>
                <div id="vhost">
                    <?php echo $html['vhost'] ?>
                </div>
            </div>
            <div class="summary-noline">
                <h2>IP</h2>
                <div id="ip">
                    <?php echo $html['ip'] ?>
                </div>
            </div>

            <br style="clear: both;"/>
            <div style="border-top: 1px dashed #000;">
                <h2>Files</h2>
                <div id="file">
                    <?php echo $html['file'] ?>
                </div>
            </div>
        </div>
        <br style="clear: both;"/>

        <div id="tabs">
            <ul>
                <?php foreach ($stati as $key=>$server): ?>
                    <li><a href="#<?php echo $key ?>"><em><?php echo $key; ?></em></a></li>
                <?php endforeach; ?>
            </ul>
            <div>
                <?php foreach ($stati as $key=>$server): ?>
                    <div id="<?php echo $key ?>"><?php echo $server['status'] ? $server['status'] : ' This server is down! Could not get status page.' ?></div>
                <?php endforeach; ?>
            </div>
        </div>

        <div id="dialog" title="settings">
            <p>
                <label for="amount">Refresh time (seconds):</label>
                <input type="text" id="amount" value="" />
            </p>

            <div id="slider"></div>
        </div>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js"></script>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.12/jquery-ui.min.js"></script>
        <script type="text/javascript" src="js/base.js"></script>
        <script type="text/javascript">
            var refreshTime = refreshTimeSetting = <?php echo $refreshSeconds ?>;
        </script>
    </body>
</html>
